import { Injectable, EventEmitter, Host } from '@angular/core';
import { BaseHttpService } from '../../shared/services/baseHttp.service';
import { HttpClient, HttpParams } from '@angular/common/http';
import { StorageService } from '../../shared/services/storage.service';
import { Observable } from 'rxjs';
import { AppComponent } from '../../app.component';

export enum LongRunningTaskInstanceStatusEnum {
    Scheduled = 1,
    Running = 2,
    Finished = 3,
    Failed = 4,
    Cancelled = 5
}

export enum LongRunningTaskTypeEnum {
    GccsReportPdf = 1,
    PiReportPdf = 2,
    ESGRatingAdminCheckReport = 3,

    PortfolioExportExcel = 4,
    PortfolioSecuritiesDownloadTemplate = 5,
    WeightMatrixDownload = 6,
    PortfolioSecuritiesUpload = 7,
    WeightMatrixUpload = 8,

    ScreeningToolExcel = 100,
    ScreeningToolCSV = 101,
    ESGCompanyReportPDF = 199,
    CompanyReportPDF = 200,
    InsightsPDF = 201,
    CorporateGovernancePDF = 202,
    ControversyReportPDF = 203,
    RiskRatingsReport = 204,
    GovernancePDFS3 = 205,

    ValidationRulesWhiteListCSV = 210,
    PortfolioMatchedSecuritiesDownload = 211
}

/**
 * Long Running Task Manager main component
 *
 * Author: Sorin Spiru
 * Date: 13.01.2018
 */
@Injectable()
export class LrtmService extends BaseHttpService {
    private static _tasks: any[] = [];
    private static _maxTasks: number = 0;
    private serviceLink: string = "lrtmserv/api/v1/task";
    public tasksStatusUpdated: EventEmitter<any[]> = new EventEmitter();

    public set tasks(value: any[]) {
        LrtmService._tasks.forEach(x => {
            value.forEach(y => {
                if (y.id == x.id && y.taskInstanceStatus != x.taskInstanceStatus) {
                    this.tasksStatusUpdated.emit(y);
                }
            });
        });
        LrtmService._tasks = value;
    }

    public get tasks() {
        return LrtmService._tasks;
    }

    constructor(private http: HttpClient) {
        super();
    }

    /**
     * Delete task
     * @param id Task unique identifier
     */
    public deleteTask(id: string): Observable<string> {
        //TODO: cancel upload
        return this.http.delete(this.serverUrl + 'lrtmserv/api/v1/task/' + id, { responseType: 'text' });
    }

    /**
     * Doawnload task result
     * @param id Task unique identifier
     */
    public downloadResult(id: string): void {
        let auth = StorageService.get().authData;

        let params: HttpParams = new HttpParams();
        params = params.set("taskInstanceId", id)
            .set("getResult", 'true')
            .set("deleteOnGetResult", 'true')
            .set("access_token", auth.access_token);

        //if IE, open download window is new tab, else in self
        window.open(this.serverUrl + this.serviceLink + '?' + params.toString(), this.detectIeVersion() != -1 ? '_blank' : '_self');
    }

    /**
     * Run task
     * @param reportName Name of report
     * @param reportType Report type
     * @param params Task parameters
     * @param isDownload True for download task and false for upload
     * @param filesToUpload Array of files to upload if 'isDownload' is set to false
     */
    public runTask(rootComponent: AppComponent, reportName: string, reportType: LongRunningTaskTypeEnum, params: any, isDownload: boolean, filesToUpload?: File[]): Observable<any> {        
        if (LrtmService._tasks.length >= LrtmService._maxTasks) {            
            rootComponent.showWarning('You have exceeded the maximum number of simultaneous operations. Please finalize one of the items below before initiating a new operation.', 'Warning');
            return Observable.of(null);
        }
        else {
            var postData = {
                id: this.generateUUID(),
                title: reportName,
                paramJson: typeof params == "string" ? params : JSON.stringify(params),
                taskType: reportType,
                mimeType: "",
                isUpload: !isDownload,
                isDownload: isDownload,
                order: LrtmService._tasks.length
            };
            let isIE9 = this.detectIeVersion() == 9;

            let queryParams: HttpParams = new HttpParams();
            if (isIE9)
                queryParams = queryParams.set("isIe", isIE9.toString());
            let body: FormData = new FormData();
            body.set('data', JSON.stringify(postData));
            if (!isDownload) {
                filesToUpload.forEach((file, index) => {
                    body.set('fileUpload' + index, file);
                });
            }

            return this.http.post<any>(this.serverUrl + this.serviceLink + '?', body, { params: queryParams });
        }
    }

    public finishTask(queryParams: any): any {
        let params: HttpParams = new HttpParams();
        params = params.set("taskInstanceId", queryParams.taskInstanceId)
            .set("overallStatus", queryParams.overallStatus)
            .set("getStatus", queryParams.getStatus)
            .set("getResult", queryParams.getResult)
            .set("deleteOnGetResult", queryParams.deleteOnGetResult);
        return this.http.get(this.serverUrl + this.serviceLink + '?', { params: params, responseType: 'text' });;
    }

    private generateUUID() {
        var d = new Date().getTime();
        var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
            var r = (d + Math.random() * 16) % 16 | 0;
            d = Math.floor(d / 16);
            return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
        });
        return uuid;
    }

    public setMaxTasksPerUser() {
        //get max number of tasks allowed per user
        this.http.get<any>(this.serverUrl + '/lrtmserv/api/v1/taskManagerSettings').subscribe(data => {
            LrtmService._maxTasks = data.maxTasksPerUser;
        })
    }
    
    private detectIeVersion(): number {
        var ua = window.navigator.userAgent;                   
        var msie = ua.indexOf('MSIE ');
        if (msie > 0) {
          // IE 9 or older => return version number
          return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
        }
      
        var trident = ua.indexOf('Trident/');
        if (trident > 0) {
          // IE 11 => return version number
          var rv = ua.indexOf('rv:');
          return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
        }
      
        var edge = ua.indexOf('Edge/');
        if (edge > 0) {
          // Edge (IE 12+) => return version number
          return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
        }      
        // other browser
        return -1;
    }
}